package com.touchfired.common.core.publisher;

import com.touchfired.common.core.callback.Callback;
import com.touchfired.common.core.event.BaseEvent;
import com.touchfired.common.core.listener.Listener;
import com.touchfired.common.spring.BeanLocator;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.core.annotation.AnnotationAwareOrderComparator;

import java.lang.reflect.ParameterizedType;
import java.util.*;

/**
 * 基础发布器
 * @author 幸佳俊
 */
@SuppressWarnings({"rawtypes", "unchecked"})
public abstract class BasePublisher implements Publisher {

    /** 所有监听器，<事件全包名，该事件所有监听器> */
    public static Map<String, List<Listener>> listeners = new HashMap<>();

    /**
     * 初始化监听器
     */
    public static void initListeners() {
        List<Listener> beanListener = new ArrayList<>(BeanLocator.getBeanOfType(Listener.class));
        AnnotationAwareOrderComparator.sort(beanListener);
        for (Listener listener : beanListener) {
            ParameterizedType pt = (ParameterizedType) listener.getClass().getGenericSuperclass();
            String eventName = pt.getActualTypeArguments()[0].getTypeName();
            List<Listener> listenerList = listeners.get(eventName);
            if (CollectionUtils.isEmpty(listenerList)) {
                listenerList = new LinkedList<>();
            }
            listenerList.add(listener);
            listeners.put(eventName, listenerList);
        }
    }

    /**
     * 发布事件
     * @param event 指定事件
     * @param callback 处理事件时回调
     */
    @Override
    public void publishEvent(BaseEvent event, Callback callback) {
        String eventName = event.getClass().getName();
        List<Listener> listenerList = listeners.get(eventName);
        if (CollectionUtils.isNotEmpty(listenerList)) {
            for (Listener listener : listenerList) {
                listener.onEvent(event, callback);
            }
        }
    }

    /**
     * 发布事件
     * @param event 指定事件
     * @return 任一回调对象
     */
    public abstract Object publish(BaseEvent event);

}
